﻿using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;

namespace MediaBot.Library
{
    public class CustomWebReponse : IDisposable
    {
        public int ContentLength { get; private set; }
        //private string _contentType;
        private string _header;
        private WebHeaderCollection Headers { get; set; }
        public bool KeepAlive { get; private set; }
        public Uri ResponseUri { get; private set; }
        public Socket Socket { get; private set; }

        public void Connect(CustomWebRequest request)
        {
            ResponseUri = request.RequestUri;

            Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //var remoteEp = new IPEndPoint(Dns.Resolve(ResponseUri.Host).AddressList[0], ResponseUri.Port);
            var remoteEp = new IPEndPoint(Dns.GetHostEntry(ResponseUri.Host).AddressList[0], ResponseUri.Port);
            Socket.Connect(remoteEp);
        }

        public void SendRequest(CustomWebRequest request)
        {
            ResponseUri = request.RequestUri;
            request.Header = request.Method + " " + ResponseUri.PathAndQuery + " HTTP/1.0\r\n" + request.Headers + "\r\n";

            if (request.Cookies.Count > 0)
            {
                string cookieString = " Cookie: " + request.GetCookies();
                request.Header += cookieString;
            }

            Socket.Send(Encoding.ASCII.GetBytes(request.Header));
        }

        public void SetTimeout(int timeout)
        {
            Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, timeout*1000);
            Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, timeout*1000);
        }

        public void ReceiveHeader()
        {
            _header = "";
            Headers = new WebHeaderCollection();

            var bytes = new byte[10];
            while (Socket.Receive(bytes, 0, 1, SocketFlags.None) > 0)
            {
                _header += Encoding.ASCII.GetString(bytes, 0, 1);
                if (bytes[0] == '\n' && _header.EndsWith("\r\n\r\n"))
                    break;
            }
            MatchCollection matches = new Regex("[^\r\n]+").Matches(_header.TrimEnd('\r', '\n'));
            for (int n = 1; n < matches.Count; n++)
            {
                string[] strItem = matches[n].Value.Split(new[] {':'}, 2);
                if (strItem.Length > 0)
                    Headers[strItem[0].Trim()] = strItem[1].Trim();
            }

            // check if the page should be transfered to another location
            if (matches.Count > 0 )
            {
                Match redirectMatch = Regex.Match(matches[0].Value, " 30[1237] ", RegexOptions.IgnorePatternWhitespace);
                if (redirectMatch.Value != string.Empty)
                {
                    // check if the new location is sent in the "location" header
                    if (Headers["Location"] != null)
                        try
                        {
                            ResponseUri = new Uri(Headers["Location"]);
                        }
                        catch
                        {
                            ResponseUri = new Uri(ResponseUri, Headers["Location"]);
                        }
                }
            }
            //string _contentType = Headers["Content-Type"];
            if (Headers["Content-Length"] != null)
                ContentLength = int.Parse(Headers["Content-Length"]);
            KeepAlive = (Headers["Connection"] != null && Headers["Connection"].ToLower() == "keep-alive") ||
                        (Headers["Proxy-Connection"] != null && Headers["Proxy-Connection"].ToLower() == "keep-alive");
        }

        private void Close()
        {
            if (Socket == null) return;

            if (Socket.Connected) Socket.Disconnect(false);
            Socket.Close();

            Socket.Dispose();
        }

        public void Dispose()
        {
            Close();
        }
    }
}